﻿//  --------------------------------
//  Copyright (c) AW Systems, Inc. All rights reserved.
//  This source code is made available under the terms of the Microsoft Public License (Ms-PL)
//  http://www.codeplex.com/SLAM/license
//  ---------------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.SharePoint;
using System.Reflection;
using System.Xml;

namespace Slam.FieldTypes
{
	/// <summary>
	/// Field containing an application wide ListItem identifier used by SLAM.
	/// </summary>
	public class SlamIdField : SPFieldText
	{
		/// <summary>
		/// Indicates whether this field should be automatically assigned an ID
		/// </summary>
		public bool GenerateValue
		{
			get
			{
				bool generateValue = false;
				object oldFieldAttribute = this.GetFieldAttributeValueInternal("GenerateValue");
				object fieldAttribute = this.GetFieldAttributeValueInternal("GenerateValue", "aws");
				if (fieldAttribute != null)
				{
					bool.TryParse(fieldAttribute.ToString(), out generateValue);
				}
				else if (oldFieldAttribute != null)
				{
					bool.TryParse(oldFieldAttribute.ToString(), out generateValue);
				}
				return generateValue;
			}
			set
			{
				this.SetFieldAttributeValueInternal("aws:GenerateValue", "aws", value.ToString());
			}
		}

		/// <summary>
		/// Indicates whether this field should be shown in New and Edit Forms
		/// </summary>
		public bool ShowInForms
		{
			get
			{
				bool showInForms = false;
				object oldFieldAttribute = this.GetFieldAttributeValueInternal("ShowInForms");
				object fieldAttribute = this.GetFieldAttributeValueInternal("ShowInForms", "aws");
				if (fieldAttribute != null)
				{
					bool.TryParse(fieldAttribute.ToString(), out showInForms);
				}
				else if (oldFieldAttribute != null)
				{
					bool.TryParse(oldFieldAttribute.ToString(), out showInForms);
				}
				return showInForms;
			}
			set
			{
				this.SetFieldAttributeValueInternal("aws:ShowInForms", "aws", value.ToString());
			}
		}
		
		public SlamIdField(SPFieldCollection fields, string fieldName)
			: base(fields, fieldName)
		{
			
		}

		public SlamIdField(Microsoft.SharePoint.SPFieldCollection fields, string typeName, string displayName)
			: base(fields, typeName, displayName)
		{
			
		}

		public override void OnAdded(SPAddFieldOptions op)
		{
			base.OnAdded(op);
			if (!this.ShowInViewForms.HasValue || (ShowInViewForms.HasValue && !ShowInViewForms.Value))
			{
				this.ShowInViewForms = false;
				Update();
			}
		}

		public override Microsoft.SharePoint.WebControls.BaseFieldControl FieldRenderingControl
		{
			get
			{
				SlamIdFieldControl control = new SlamIdFieldControl();
				control.FieldName = InternalName;
				control.GenerateValue = GenerateValue;
				control.ShowInForms = ShowInForms;

				return control;
			}
		}

		/// <summary>
		/// Gets an attribute value by name and namespace from the Field's underlying XML.
		/// </summary>
		/// <param name="attribute">Attribute name</param>
		/// <param name="namespaceUri">Attribute namespace</param>
		/// <returns>Attribute value</returns>
		internal string GetFieldAttributeValueInternal(string attribute, string namespaceUri)
		{
			Type slamIdFieldType = typeof(SlamIdField);
			PropertyInfo slamIdFieldNode = slamIdFieldType.GetProperty("Node", BindingFlags.Instance | BindingFlags.NonPublic);

			return GetNamedStringItemInternal(((XmlNode)slamIdFieldNode.GetValue(this, null)), attribute, namespaceUri);
		}

		/// <summary>
		/// Gets an attribute value by name from the Field's underlying XML.
		/// </summary>
		/// <param name="attribute">Attribute name</param>
		/// <returns>Attribute value</returns>
		internal string GetFieldAttributeValueInternal(string attribute)
		{
			Type slamIdFieldType = typeof(SlamIdField);
			MethodInfo method = slamIdFieldType.GetMethod("GetFieldAttributeValue", BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] { typeof(string) }, null);
			object attributeValue = method.Invoke(this, new object[] { attribute });
			return attributeValue == null ? "" : attributeValue.ToString();
		}

		/// <summary>
		/// Gets string value of attribute with the given name and namespace from the given XmlNode.
		/// </summary>
		/// <param name="node">Node with attribute</param>
		/// <param name="localName">Attribute LocalName</param>
		/// <param name="namespaceUri">Attribute Namespace prefix</param>
		/// <returns>Attribute value</returns>
		internal static string GetNamedStringItemInternal(XmlNode node, string localName, string namespaceUri)
		{
			XmlAttributeCollection attributes = node.Attributes;
			XmlNode namedItem = attributes.GetNamedItem(localName, namespaceUri);
			return namedItem == null ? null : namedItem.Value;
		}

		/// <summary>
		/// Sets attribute with the given name and namespace in the Field's underlying XML to the given value.
		/// </summary>
		/// <param name="attribute">Attribute name</param>
		/// <param name="namespaceUri">Attribute namespace prefix</param>
		/// <param name="value">Attribute value</param>
		internal void SetFieldAttributeValueInternal(string attribute, string namespaceUri, string value)
		{
			Type slamIdFieldType = typeof(SlamIdField);
			PropertyInfo slamIdFieldNode = slamIdFieldType.GetProperty("Node", BindingFlags.Instance | BindingFlags.NonPublic);
			SetNamedStringItemInternal(((XmlNode)slamIdFieldNode.GetValue(this, null)).OwnerDocument, ((XmlNode)slamIdFieldNode.GetValue(this, null)), attribute, namespaceUri, value);
		}

		/// <summary>
		/// Sets attribute with the given name in the Field's underlying XML to the given value
		/// </summary>
		/// <param name="attribute"></param>
		/// <param name="value"></param>
		internal void SetFieldAttributeValueInternal(string attribute, string value)
		{	
			Type typeFromHandle = typeof(SlamIdField);
			MethodInfo method = typeFromHandle.GetMethod("SetFieldAttributeValue", BindingFlags.Instance | BindingFlags.NonPublic);
			method.Invoke(this, new object[] { attribute, value });
		}

		/// <summary>
		/// Sets attribute in the given XmlNode in the given XmlDocument with the given name and namespace to the given value.
		/// </summary>
		/// <param name="document">XML document containing the node with the attribute to set</param>
		/// <param name="node">Node containing the attribute to set</param>
		/// <param name="localName">Attribute name</param>
		/// <param name="namespaceUri">Attribute namespace prefix</param>
		/// <param name="value">Attribute value</param>
		/// <returns></returns>
		internal string SetNamedStringItemInternal(XmlDocument document, XmlNode node, string localName, string namespaceUri, string value)
		{	
			XmlNode namedItem = node.Attributes.GetNamedItem(localName, namespaceUri);
			if (namedItem != null)
			{
				namedItem.Value = value;
			}
			else
			{
				XmlAttribute xmlAttribute = document.CreateAttribute(localName, namespaceUri);
				xmlAttribute.Value = value;
				node.Attributes.SetNamedItem(xmlAttribute);
			}
			return value;
		}
	}
}